Bundled libc
~~~~~~~~~~~~
sninit comes with a stripped-down subset of dietlibc providing minimal
startup code, syscalls and standard libc routines.

Reasons for including libc:

1. Tiered dependencies.
   Init is the first process to start, and thus should better
   not rely on anything else to be available, including any libs.
   This was extended to build-time dependencies as well, in that
   init can be built without any libs available for the target system.

2. Clear set of dependencies.
   sninit depends on bunch of syscalls and a very small subset of libc.
   How small? Well bundled libc shows exactly how small it is.

3. Clean code.
   Generic libc (even dietlibc) needs a lot of cruft in it to ensure
   compatibility with arbitrary code.
   sninit is not some arbitrary code, so the cruft can be trimmed off.

4. Full source for debugging.
   Ok, this is a bit vain but I like to have source code available
   when gdb stops somewhere in the middle of a libc call.

   With some effort, this can be achieved even for a generic libc,
   but it's rarely done. And generic libc tends to be rather unreadable
   anyway due to being generic.

On the downside, bundled libc means explicit architecture requirements
and more code to test.


Headers
~~~~~~~
Bundled libc keeps standard libc header structure (20+ files).
It makes little sense as far as only this libc and sninit are concerned,
but I want to keep sninit compatible with standard libc, and the bundled
libc a drop-in replacement for a generic one.


Arch-dependent constants in bits/
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For reasons beyond my comprehension, some ostensibly random kernel constants
have different values for different architectures; sparc and mips in particular
stand out.

The kernel (and dietlibc) approach to this is apparently a lot of #ifdefs,
a pretty ugly solution in my opinion. The bundled libc uses independent bits/
directory for each architecture. Stuff gets copied of course, but on
the other hand, a change in on arch files does not affect others.


No cpp / assembler-only files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Bundled libc uses .equ to define constants in assembler files.
This is in contrast with dietlibc which uses C-preprocessed assembler
and musl which uses inline assembler in C files.

Linux in general is assembler-unfriendly, with lots of stuff being
declared in C headers. And C preprocessor just does not play well
when paired with assembler, dropping (significant) newlines and producing
ugly source listings in debugger.

So the decision was to put everything in nice and clean .s files.

Declaring constants in assembler leads to some code duplication,
and requires checks to ensure they stay in sync with bits/syscall.h
Those values however are surprisingly stable in linux, as changing them
would wreak havoc upon production systems, so I see this as the lesser evil.

Same goes for structure member offsets. The code won't survive a change
in kernel headers, but neither will something close to 100% of all linux
installations.
